.\" Copyright (c) 2010 AFP Authors
.\" This source code is released under the terms of the
.\" MIT license. Please see the file LICENSE for license details.

.TH AFP 3 "DECEMBER 2010" PSU "User Manuals"
.SH NAME 
afp-dev \- afp filter development guide
.SH OVERVIEW
This guide aims to provide a brief walk through of the filter
creation process.

Every filter has a type: 
.IR Source ", " Link ", or " Sink
which indicates whether they pull audio into the pipeline, 
process audio data, or dispatch audio data elsewhere.

Filters may be developed as stand alone executables in any language.
They may be run using the appropriate built in 'exec' filter, and should 
understand the format outlined in
.BR afp-fmt (5).
The rest of this document does not apply to them.

Filters may also be developed in Go as separate packages and built into 
.BR afp (1)
as follows:

.SH THE FILTER INTERFACE
.PP
.RS 0
type Filter interface {
.RS 0
	GetType() int
.RS 0
	Init(*afp.Context, []string) os.Error
.RS 0
	Start()
.RS 0
	Stop() os.Error
.RS 0
}

Every filter must import the "afp" package
and implement the afp.Filter interface.  The
purpose of each method required is as follows:

.SS GetType() int
Should return one of 
.BR afp.PIPE_SOURCE ", " afp.PIPE_LINK ", or " afp.PIPE_SINK
depending on the purpose of the filter.

.SS Init(*afp.Context, []string) os.Error
Will be passed a pointer to a context object as outlined below,
and a slice of strings holding the arguments passed to this filter.
Argument parsing, if needed, should be done here.
No reads/writes on the channels held in the 
.B Context
object should occur in Init.
Any error returned from Init will cause 
.BR afp (1)
to exit immediately with the error's message

.SS Start()
Will hold or call all audio processing routines.
Its behavior will vary depending on the type of the filter,
but should look something like:
.PP
.RS 0
header := <-context.HeaderSource //Except in Sources
.RS 0
//Modify header if needed
.RS 0
context.HeaderSink <- newHeader //Except in Sinks
.RS 0

.RS 0
for inputAvailable {
.RS 0
		frame := <-context.Source
.RS 0
		//Process frame
.RS 0
		context.Sink <- frame
.RS 0
}

Note that frames should not be modified after being sent, if 
access to multiple frames is necessary, they should be explicitly 
buffered and sent only when they've passed out of the window.

Any panics thrown in start will be caught by the pipeline manager
and cause an orderly shutdown of the pipe.  If a goroutine invoked
in 
.B Start()
panics, it will not be caught, and may cause file corruption.  Therefor
when possible goroutines should send errors to the calling Start(), which
can panic on their behalf.

To avoid spinning, all channel reads and writes in Start should be blocking.

.SS Stop() os.Error
This method will be called if some filter causes an unplanned shutdown of the 
pipeline.  It should end processing in a sane way if possible, and return any
errors encountered while doing so.  Errors will be displayed to the user as part 
of the error trace.

.SH THE CONTEXT OBJECT
.PP
.RS 0
type Context struct {
.RS 0
	HeaderSource <-chan StreamHeader
.RS 0
	HeaderSink   chan<- StreamHeader
.RS 0
	Source       <-chan [][]float32
.RS 0
	Sink         chan<- [][]float32
.RS 0

.RS 0
	Verbose   bool
.RS 0
	Err, Info *log.Logger
.RS 0
}

Every thread will be passed a
.B *afp.Context 
during initialization, it should store this locally.  
This object holds the channels used to communicate with other 
pieces of the pipeline, as will as logging utilities.

Generally, messages should be written to the Info logger only if 
.B Verbose
is true.  Any non-fatal errors should be reported using the Err
logger. Fatal errors may cause writes to Err, but should also 
cause a panic as outlined above.

.SH THE STREAM HEADER
.PP
.RS 0
type StreamHeader struct {
.RS 0
	Version       int8
.RS 0
	Channels      int8
.RS 0
	SampleSize    int8
.RS 0
	SampleRate    int32
.RS 0
	FrameSize     int32
.RS 0
	ContentLength int64
.RS 0
}

The StreamHeader holds the header information as outlined in 
.BR afp-fmt (5)

.SS Version
The header version. Future header versions may be incompatible.

.SS Channels
The number of channels of audio data, usually 1 or 2, but may be
as large as 127.

.SS SampleSize
The number of bits used to store each channel sample. Currently always 32.

.SS FrameSize
The number of time slices per frame.

.SS Content Length
The length in bytes of the content which follows. If the value is unknown
this field will be 0.		

.SH THE CONSTRUCTOR METHOD
Every filter must have an associated method which returns a usable instance.
This method should have the signature 
.B func() afp.Filter


.SH REBUILDING AFP
Filters may be built outside the afp source tree by any method,
or copied into a subdirectory of filters dir.  In the latter case
the afp build script will take care of building and installing 
the filter.  The filter subdirectory should contain a makefile
with a standard name with default target that builds the filter.
It is also advised to include install and clean targets.

.P
In order to be included
in the afp executable the file 
.I /afp/source/path/main/filterlist.go
must be modified and the executable rebuilt:
.P
- Add the path to the new filter package to the import block
.P
- Add an entry to the filterlist map for each filter defined.  The key of this map 
will be the name of the filter on the command line.  The value must be a function
which returns the associated filter as described above.
.P 
- Run 
.I make && make install
with environment variables as described in BUILDING.
This script will rebuild the afp libraries, filters, and finally main. 
This will attempt to create files in the Go package tree and may need super user
permissions to do so.
.P
-
.I Optional:
You may wish to add a description of your filter to the 
.BR	afp (1) 
manpage.  To do so edit 
.I doc/afp.man
before running running make as described above.

.SH PITFALLS
Attempting to read from a channel in the context object in the 
Init method will cause a deadlock.

.SH AUTHORS
Aaron Devore <aaron.devore@gmail.com>
.br
John Harker <kjharke@cs.pdx.edu>
.br
Cory Kolbeck <ckolbeck@cs.pdx.edu>
.br
Eric O'Connell <eric@zerominuszero.net>
.SH "SEE ALSO"
.BR afp (1),
.BR afp-fmt (5)
